namespace Bowlus.AppHost
{
    using System;
    using System.Diagnostics;
    using System.Linq;

    using Bowlus.Common;
    using Bowlus.Common.Communications;

    using Microsoft.Practices.Unity;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.Diagnostics;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using System.Threading;

    public class WebRole : RoleEntryPoint
    {
        private AppHostManager appHostManager;

        private CommunicationServiceHost communicationServiceHost;

        public override bool OnStart()
        {
            ConfigureDiagnostics();

            RoleEnvironment.Changing += RoleEnvironmentChanging;
            RoleEnvironment.Changed += this.RoleEnvironment_Changed;

            try
            {
                Trace.TraceInformation("Starting apphost web role.");
                var unityContainer = BowlusContainer.Current.GetInstance<IUnityContainer>();
                ContainerBootstrapper.RegisterTypes(unityContainer);
                this.appHostManager = unityContainer.Resolve(typeof(AppHostManager)) as AppHostManager;

                Trace.TraceInformation("Resolved AppHostManager.");
                Debug.Assert(this.appHostManager != null, "deploymentManager != null");
                this.communicationServiceHost = new CommunicationServiceHost(this.appHostManager.MessageHandler);
                
                this.appHostManager.Initialize();
                Trace.TraceInformation("Apphost web role started.");
            }
            catch (Exception exception)
            {
                Trace.TraceError(string.Format("Error while initializing the deployment manager. {0}", exception));
            }

            return base.OnStart();
        }

        private void RoleEnvironment_Changed(object sender, RoleEnvironmentChangedEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentTopologyChange))
            {
                var topoogyChanges = e.Changes.Where(change => change is RoleEnvironmentTopologyChange);

                Trace.TraceInformation("Topology change detected in APPHOST.");

                foreach (var topologyChange in topoogyChanges.OfType<RoleEnvironmentTopologyChange>())
                {
                    Trace.TraceInformation("Topology change {0}", topologyChange.RoleName);
                }
            }
        }

        public override void OnStop()
        {
            // Here we will assume an instance has the opportunity to inform the frontend that it is
            // stopping. Any scenario beyond that should extend this design.
            if (null != this.communicationServiceHost)
            {
                this.communicationServiceHost.Dispose();
            }

            //SendStatusMessage(BowlusMessageType.AppHostShuttingDown);
            base.OnStop();
        }

        private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                e.Cancel = e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(Settings.ShouldRecycleInstance);
            }
            else if (e.Changes.Any(change => change is RoleEnvironmentTopologyChange))
            {
                e.Cancel = false;
            }
        }

        private static void ConfigureDiagnostics()
        {
            var config = DiagnosticMonitor.GetDefaultInitialConfiguration();

            CrashDumps.EnableCollection(true);

            config.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);

            // For windows azure logs
            config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
            config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;

            var cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"));

            DiagnosticMonitor.Start(cloudStorageAccount, config);
            Trace.Listeners.Add(new DiagnosticMonitorTraceListener());

            Trace.TraceInformation("Configured Windows Azure Diagnostics");
        }
    }
}
